#include <iostream>
#include <list>
using namespace std;

//以下是观察者和主题的基类，其中 DisplayElement 是一个抽象类,用来使子类实现显示功能
class Observer
{
public:
   virtual ~Observer(){};
   virtual void update(float temp, float humidity, float pressure){};
};

class DisplayElement
{
public:
   virtual ~DisplayElement(){};
   virtual void display() = 0;
};

class Subject
{
public:
   virtual ~Subject(){};
   virtual void regsiterObserver(Observer * o){};
   virtual void removeObserver(Observer * o){};
   virtual void notifyObserver(){};
};

//以下是WeatherData类，实现了注册，删除和通知观察者的功能。
class WeatherData : public Subject
{
public:
   void regsiterObserver(Observer* o)
   {
      observers.push_back(o);
   }

   void removeObserver(Observer* o)
   {
      observers.remove(o);
   }

   void notifyObservers()
   {
      list<Observer*>::iterator iter = observers.begin();
      for(; iter != observers.end(); ++iter){
         Observer * observer = *iter;
         observer->update(tempreature,humidity, pressure);
      }
   }

   void measurementsChanged()
   {
      notifyObservers();
   }

   void setMeasurements( float temp, float humid, float pres)
   {
      tempreature= temp;
      humidity= humid;
      pressure= pres;
      measurementsChanged();
   }

private:
   list<Observer*> observers;
   float tempreature;
   float humidity;
   float pressure;
};

//以下是CurrentConditionsDisplay布告板的实现，主要功能为申请注册，实时更新和显示。
class CurrentConditionsDisplay : public Observer, public DisplayElement
{
public:
   CurrentConditionsDisplay(Subject * weather_Data)
   {
      weatherData = weather_Data;
      weatherData->regsiterObserver(this);
   }

   void update(float temp, float humid, float pres)
   {
      tempreature = temp;
      humidity = humid;
      display();
   }

   void display()
   {
      cout<< "Current conditions: "<< tempreature
         <<"F degree and " << humidity<< "% humidity" <<endl;
   }

private:
   float tempreature;
   float humidity;
   Subject * weatherData;
};

/*客户代码*/
int main()
{
   WeatherData * weatherData = new WeatherData();
   CurrentConditionsDisplay * currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);

   weatherData->setMeasurements(80,65, 30.4f);
   weatherData->setMeasurements(82,70, 29.2f);
   weatherData->setMeasurements(78,90, 29.2f);
   return 0;
}
